// ///////////////////////////// MIT License //////////////////////////////////// //
//                                                                                //
// Copyright (c) 2010 David Zsolt Manrique                                        //
//                    david.zsolt.manrique@gmail.com                              //
//                                                                                //
// Permission is hereby granted, free of charge, to any person obtaining a copy   //
// of this software and associated documentation files (the "Software"), to deal  //
// in the Software without restriction, including without limitation the rights   //
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell      //
// copies of the Software, and to permit persons to whom the Software is          //
// furnished to do so, subject to the following conditions:                       //
//                                                                                //
// The above copyright notice and this permission notice shall be included in     //
// all copies or substantial portions of the Software.                            //
//                                                                                //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR     //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,       //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE    //
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER         //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  //
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN      //
// THE SOFTWARE.                                                                  //
//                                                                                //
// ////////////////////////////////////////////////////////////////////////////// //

//!
//! classes and functions for simple io saving,loading and cmd line parsing 
//! version 0.4
//! 

#ifndef SIMPLE_IO_H
#define SIMPLE_IO_H

#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <algorithm>
#include <iomanip>
#include <vector>
#include <list>
#include <set>
#include <cstdarg>
#include <stdexcept>

//! simple io namespace
namespace io
{

//! conversion function without error check
//! @param fr from
//! @return to
template<typename To,typename Fr>
To to(const Fr & fr)
{
	To to;
	std::stringstream ss;
	ss<<fr;
	ss>>to;
	return to;
}

//! load each line from a file ignoring commented parts
//! @param ifn input file name
//! @param comment comment string literal, everyting after comment will be ignored
//! @param lines output string vector that contains each line in the file
inline void load(std::string ifn,std::string comment,std::vector<std::string> & lines) 
{ 
	std::ifstream ifs(ifn.c_str());
	std::string line;
	lines.clear();
	while(std::getline(ifs,line))
	{
		line = line.substr(0,line.find(comment));
		line.erase(line.find_last_not_of("\n\t\v\f\r ")+1);
		line.erase(0, line.find_first_not_of("\n\t\v\f\r "));
		lines.push_back(line);
	}
	ifs.close();
} 
//! load each line from a file ignoring commented parts
//! @param is input stream
//! @param comment comment string literal, everyting after comment will be ignored
//! @param lines output string vector that contains each line in the file 
inline void load(std::istream & is,std::string comment,std::vector<std::string> & lines) 
{ 
	std::string line;
	lines.clear();
	while(std::getline(is,line))
	{
		line = line.substr(0,line.find(comment));
		line.erase(line.find_last_not_of("\n\t\v\f\r ")+1);
		line.erase(0, line.find_first_not_of("\n\t\v\f\r "));
		lines.push_back(line);
	}
}

//! extract lines between two block markers
//! @param block_begin a string that marks the begining of the block
//! @param block_end marks the end of the block
//! @param lines input lines that may contains the marked block
//! @param blocklines output lines between the block markers
inline bool parse_block(const std::string & block_begin,const std::string & block_end, 
                 const std::vector<std::string> & lines,std::vector<std::string> & blocklines)
{
	blocklines.clear();
	size_t i = 0;
	while(i < lines.size())
	if(lines[i].size() > 0)
	{
		if(lines[i] == block_begin)
		{
			i++;
			while(i < lines.size())
			if(lines[i].size() > 0)
			{
				if(lines[i] == block_end)
				break;
				blocklines.push_back(lines[i]);
				i++;
			}
			else i++;
			if(lines[i].empty()) return false;
			else if(lines[i] != block_end) return false;
		}
	i++;
	}
	else i++;
	return true;
}



//! input stream class, that either open a file or uses std input.
struct input_stream
{
private:
	std::ifstream * pifs_;
	std::istream * pis_;
public:
	//! constructor 
	//! @param filename contains the file name, if it is empty then it uses std::cin
	input_stream(const std::string & filename = "")
	{
		if(filename != "")
		{
			pifs_ = new std::ifstream(filename.c_str());
			pis_ = pifs_;
		}
		else 
			pis_ = &std::cin;
	}

	//! checks if it uses std::cin
	//! @return true if it uses std::cin
	bool is_std()
	{
		return (pis_ == &std::cin);
	}

	//! gives back istream reference
	//! @return istream referene
	std::istream & stream()
	{
		return *pis_;
	}
	
	//! destructor closes the file if is not std input
	~input_stream()
	{
		if (pis_ != &std::cin) 
		{ 
			pifs_->close(); 
			delete pifs_; 
		} 

	 
	}
};


//! output stream class, that either open a file or uses std output.
struct output_stream
{
private:
	std::ofstream * pofs_;
	std::ostream * pos_;
public:
	//! constructor 
	//! @param filename contains the file name, if it is empty then it uses std::cout
	output_stream(const std::string & filename = "")
	{
		if(filename != "")
		{
			pofs_ = new std::ofstream(filename.c_str());
			pos_ = pofs_;
		}
		else 
			pos_ = &std::cout;
	}

	//! checks if it uses std::cout
	//! @return true if it uses std::cout
	bool is_std()
	{
		return (pos_ == &std::cout);
	}
	
	//! gives back ostream reference
	//! @return ostream referene
	std::ostream & stream()
	{
		return *pos_;
	}

	//! destructor closes the file if is not std output
	~output_stream()
	{
		if (pos_ != &std::cout) 
		{ 
			pofs_->close(); 
			delete pofs_; 
		} 
	}
};


//!
//!  command line argument class
//!  this contains the argc and argv, and the help message.
//!
class arguments
{
private:
	std::list<std::string> arglist;
	std::list<std::vector<std::string> > help;
public:
	//! constructor
	//! @param argc argc from main
	//! @param argv argv from main
	arguments(int argc,char** argv)
	{
		for(int i = 1; i < argc; i++)
			arglist.push_back(argv[i]);
		arglist.push_back("--");
	}
	template<typename T>
	friend class posarg;
	template<typename T>
	friend class vararg;
	template<bool def>
	friend class switcharg;
	template<typename T>
	friend class multivararg;
	
	//! print input
	void print()
	{
		for(std::list<std::string>::iterator it = arglist.begin(); it != arglist.end(); it++)
		std::cout << *it << std::endl;
		std::cout << std::endl;
	    
	}
	//! print help messgae
	//! @param os stream
	//! @param name program name
	void print_help(std::ostream & os,const std::string & name)
	{
		int n = 0;
		os << "Usage: " << name << ' ';
		for(std::list<std::vector<std::string> > :: iterator it = help.begin(); it != help.end(); it++)
		if(it->size() == 1) os << "<arg-" << ++n << ">" << ' ';
		os << " -[option] <option-arg>" << std::endl;
		n = 0;
		for(std::list<std::vector<std::string> > :: iterator it = help.begin(); it != help.end(); it++)
		if(it->size() == 1)
		{
			std::ostringstream oss;
			oss << "<arg-" << ++n << ">";
			os << "   " << std::left << std::setw(15) << oss.str() << ' ' << std::left << std::setw(50) << (*it)[0] << std::endl;
		}
		for(std::list<std::vector<std::string> > :: iterator it = help.begin(); it != help.end(); it++)
		if(it->size() == 3)
		{
			os << "   " << std::left << std::setw(5) << (*it)[0] << ' ';
			os << std::left << std::setw(20) << (*it)[1] << ' ';
			os << std::left << std::setw(50) << (*it)[2] << std::endl;
		}
		   
	}
};

//! positioned cmd line arguments
template<typename T>
class posarg
{
private:
	T var;
	bool found;
public:
	//! constructor
	//! @param args arguments type that contains the command line input
	//! @param help simple help message for this input
	//! @param def default value of this input
	posarg(arguments & args,const char* help,const T & def) : var(def)
	{
		std::vector<std::string> help_message;
		help_message.push_back(help);
		args.help.push_back(help_message);
		found = false;
		for(std::list<std::string>::iterator it = args.arglist.begin(); it != args.arglist.end(); it++)
		if(*it != "--") 
		{
			std::istringstream is(*it);
			if ( !(is >> var) )
				throw std::runtime_error("Wrong command line arguments. Try --help!");
			args.arglist.erase(it);
			found = true;
			break;
		} else break;
	}
	//! * operator returns with the parsed value
	//! @return parsed value
	const T & operator * () const { return var; }
	//! ~ operator returns if this input was found in the cmd line.
	//! @return true if it was found
	bool operator ~ () const { return found; }
};

//! optional switch cmd line argument class
//! tempate def contains the default value true/false, if the switch was found
//! it negates
template<bool def>
class switcharg
{
private:
	bool var;
	bool found;
public:
	//! constructor
	//! @param args arguments type that contains the command line input
	//! @param s short version of the switch
	//! @param l long version of the switch
	//! @param help simple help message for this input
	switcharg(arguments & args,const char* s,const char* l,const char* help) : var(def)
	{
		std::vector<std::string> help_message;
		help_message.push_back(s);
		help_message.push_back(l);
		help_message.push_back(help);
		args.help.push_back(help_message);
		found = false;
		for(std::list<std::string>::iterator it = args.arglist.begin(); it != args.arglist.end(); it++)
		if(*it != "--") {
		if( (*it == s) || (*it == l) )
		{
			args.arglist.erase(it);
			var = !var;
			found = true;
			break;
		}} else break;
	}
	//! * operator returns with the switch value
	//! @return switched value
	const bool & operator * () const { return var; }
	//! ~ operator returns if the switch was found in the cmd line.
	//! @return true if it was found
	bool operator ~ () const { return found; }
};

//!
//! simple optional variable input argument class
template<typename T>
class vararg
{
private:
	T var;
	bool found;
public:
	//! constructor
	//! @param args arguments type that contains the command line input
	//! @param s short version of the switch
	//! @param l long version of the switch
	//! @param help simple help message for this input
	//! @param def defualt value of this input
	vararg(arguments & args,const char* s,const char* l,const char* help,const T & def) : var(def)
	{
		std::vector<std::string> help_message;
		help_message.push_back(s);
		help_message.push_back(l);
		help_message.push_back(help);
		args.help.push_back(help_message);
		found = false;
		for(std::list<std::string>::iterator it = args.arglist.begin(); it != args.arglist.end(); it++)
		if(*it != "--") {
		if( (*it == s) || (*it == l) )
		{
			if( *++it == "--")
				throw std::runtime_error("Wrong command line arguments. Try --help!");
			std::istringstream is(*it);
			if ( !(is >> var) )
				throw std::runtime_error("Wrong command line arguments. Try --help!");
			it = args.arglist.erase(it);
			args.arglist.erase(--it);
			found = true;
			break;
		}} else break;
	}
	//! * operator returns with the parsed value
	//! @return parsed value
	const T & operator * () const { return var; }
	//! ~ operator returns if the input was found in the cmd line.
	//! @return true if it was found
	bool operator ~ () const { return found; }
};


//! optional variable input argument that can occur more than once
template<typename T>
class multivararg
{
private:
	typename std::vector<T> var;
	bool found;
public:
	//! constructor
	//! @param args arguments type that contains the command line input
	//! @param s short version of the switch
	//! @param l long version of the switch
	//! @param help simple help message for this input
	//! @param def defualt value of this input
	multivararg(arguments & args,const char* s,const char* l,const char* help)
	{
		std::vector<std::string> help_message;
		help_message.push_back(s);
		help_message.push_back(l);
		help_message.push_back(help);
		args.help.push_back(help_message);
		found = false;
		for(std::list<std::string>::iterator it = args.arglist.begin(); it != args.arglist.end(); it++)
		if(*it != "--") {
		if( (*it == s) || (*it == l) )
		{
			if( *++it == "--")
				throw std::runtime_error("Wrong command line arguments. Try --help!");
			std::istringstream is(*it);
			T v;
			if ( !(is >> v) )
				throw std::runtime_error("Wrong command line arguments. Try --help!");
			var.push_back(v);
			it = args.arglist.erase(it);
			it = args.arglist.erase(--it);
			it--;
			found = true;
		}} else break;
	}
	//! * operator returns with the parsed value vector
	//! @return parsed value vector
	const std::vector<T> & operator * () const { return var; }
	//! ~ operator returns if the input was found at least once in the cmd line.
	//! @return true if it was found
	bool operator ~ () const { return found; }
};

//! range expression class for integers
//! the range expression by default is like 3,6,8:12,1 --> list of 3,6,8,9,10,11,12,1
//! note that range expression cannot contain whitespace
template<typename T>
class range_expression
{
public:
	//! list type
	typedef typename std::list<T> list_type;
private:
	list_type l;
	char d,r;
public:
	//! constructor
	//! @param d list delimiter (,)
	//! @param r range delimiter (:)
	range_expression(char d = ',',char r = ':') : d(d),r(r) {}
	//! * operator returns with the integer list reference
	//! @return list_type const reference
	const list_type & operator* () const { return l; }
	//! () operator parse out the list from a string
	//! @param m is the intput string that may contian the expression
	//! @return true if at least one list item was parsed successfully
	bool operator() (std::string m)
	{
		l.clear();
		std::replace(m.begin(),m.end(),d,' ');
		std::istringstream isd(m);
		std::string item;
		std::list<std::string> items;
		while(isd >> item) items.push_back(item);
		for(std::list<std::string>::iterator it = items.begin(); it != items.end(); it++)
		{
			std::replace(it->begin(),it->end(),r,' ');
			std::istringstream isr(*it);
			T var;
			isr >> var;
			T var_second;
			if( isr >> var_second )
			{
				for(T i = var; i <= var_second; i++)
				l.push_back(i);
			}
			else l.push_back(var);
		}
		if(!l.size()) return false;
		return true;
	}
	//! istream operator
	template<typename Type>
	friend std::istream & operator >> (std::istream & is,range_expression<Type> & expr);
};


//! istream operator for range_expression
template<typename T>
std::istream & operator >> (std::istream & is,range_expression<T> & expr)
{
	std::string m;
	if ( !(is >> m) ) return is;
	expr.l.clear();
	std::replace(m.begin(),m.end(),expr.d,' ');
	std::istringstream isd(m);
	std::string item;
	std::list<std::string> items;
	while(isd >> item) items.push_back(item);
	for(std::list<std::string>::iterator it = items.begin(); it != items.end(); it++)
	{
		std::replace(it->begin(),it->end(),expr.r,' ');
		std::istringstream isr(*it);
		T var;
		isr >> var;
		T var_second;
		if( isr >> var_second )
		{
			for(T i = var; i <= var_second; i++)
			expr.l.push_back(i);
		}
		else expr.l.push_back(var);
	}
	return is;
}

//! list expression class 
//! list expression is itmes separated by delimiters like a,b,c
//! note that list expression cannot contain whitespace
template<typename T>
class list_expression
{
public:
	//! list type
	typedef typename std::vector<T> list_type;
private:
	list_type l;
	char d;
public:
	//! constructor
	//! @param d list delimiter (,)
	list_expression(char d = ',') : d(d) {}
	//! * operator returns with the list reference
	//! @return list_type const reference
	const list_type & operator* () const { return l; }
	//! [] operator can give const access to the list items by their index [0..length-1]
	const T & operator[] (size_t index) const { return l[index]; }
	//! () operator parse out the list from a string
	//! @param m is the intput string that may contian the expression
	//! @return true if at least one list item was parsed successfully
	bool operator() (std::string m)
	{
		std::replace(m.begin(),m.end(),d,' ');
		std::istringstream isd(m);
		T item;
		while(isd >> item) l.push_back(item);
		if(!l.size()) return false;
		return true;
	}
	//! istream operator
	template<typename Type>
	friend std::istream & operator >> (std::istream & is,list_expression<Type> & expr);
};

//! istream operator for list_expression
template<typename T>
std::istream & operator >> (std::istream & is,list_expression<T> & expr)
{
	std::string m;
	if ( !(is >> m) ) return is;
	expr.l.clear();
	std::replace(m.begin(),m.end(),expr.d,' ');
	std::istringstream isd(m);
	T item;
	while(isd >> item) expr.l.push_back(item);
	return is;
}

//! marked expression class
//! it can be marked or not marked variable with one prefix character
//! note that the expression cannot contain whitespace
template<typename T,bool def=false>
class prefix_mark_expression
{
private:
	T var;
	bool mark;
	char prefix;
public:
	//! constructor
	//! @param d list delimiter (,)
	prefix_mark_expression(char prefix = '*') : prefix(prefix),mark(def) {}
	//! * operator returns with the var reference
	//! @return T const reference
	const T & operator* () const { return var; }
	//! * operator returns with the var reference
	//! @return T reference
	T & operator* () { return var; }
	//! ~ operator returns with mark
	//! @return !def
	bool  operator~ () const { return mark; }
	//! () operator parse out the list from a string
	//! @param m is the intput string that may contian the expression
	//! @return true if the string was parsed
	bool operator() (std::string m)
	{
		bool mark_t = mark;
		if(m.size() == 0) return false;
		if(m[0] == prefix) 
		{
			mark_t = !mark_t;
			m[0] = ' ';
		}
		std::istringstream isd(m);
		T var_t;
		if(!(isd >> var_t))return false;
		
		mark = mark_t;
		var = var_t;
		return true;
	}
	//! istream operator
	template<typename Type,bool def_>
	friend std::istream & operator >> (std::istream & is,prefix_mark_expression<Type,def_> & expr);
};

//! istream operator for marked_expression
template<typename T,bool def>
std::istream & operator >> (std::istream & is,prefix_mark_expression<T,def> & expr)
{
	std::string m;
	if ( !(is >> m) ) return is;
	bool mark_t = expr.mark;
	if(m.size() == 0) 
	{
		is.setstate(std::ios_base::failbit);
		return is;
	}
	if(m[0] == expr.prefix) 
	{
		mark_t = !mark_t;
		m[0] = ' ';
	}
	std::istringstream isd(m);
	T var_t;
	if(!(isd >> var_t))
	{
		is.setstate(std::ios_base::failbit);
		return is;
	}
	expr.mark = mark_t;
	expr.var = var_t;
	return is;
}



//! match function
//! it matches a pattern against a string
//! @param pattern contains the pattern, the output pattern %1 (%2,%3,...)
//! @param m contains the string
//! @param p1 output pointer with T type that takes the value form %1
//! @return true if match was succesfull
//! TODO if it does not match it should not change the parameters
//! TODO temmplate specialization for string->faster
//! TODO c++0x standard variadic template...
template<typename T1>
bool match(const std::string & pattern,const std::string & m,T1*p1)
{
	std::istringstream sp(pattern),sm(m);
	std::string s,s1;
	while(sp >> s)
	if( s == "%1" ) { if( ! (sm >> *p1) ) return false; continue;     }
	else { if ( (!(sm >> s1)) || (s1 != s) ) return false; }
	return true;
}
template<typename T1>
bool match(const std::string & pattern,const std::string & m,std::vector<T1>*p1)
{
	std::istringstream sp(pattern),sm(m);
	std::string s,s1;
	while(sp >> s)
	if( s == "%1" ) 
	{ 
		T1 t1;
		p1->clear();
		while(sm >> t1) p1->push_back(t1);
	}
	else { if ( (!(sm >> s1)) || (s1 != s) ) return false; }
	return true;
}
template<typename T1,typename T2>
bool match(const std::string & pattern,const std::string & m,T1*p1,T2*p2)
{
	std::istringstream sp(pattern),sm(m);
	std::string s,s1;
	while(sp >> s)
	if( s == "%1" ) { if( ! (sm >> *p1) ) return false; continue; }
	else if( s == "%2" ) { if( ! (sm >> *p2) ) return false; continue; }
	else { if ( (!(sm >> s1)) || (s1 != s) ) return false; }
	return true;
}
template<typename T1,typename T2>
bool match(const std::string & pattern,const std::string & m,T1*p1,std::vector<T2>*p2)
{
	std::istringstream sp(pattern),sm(m);
	std::string s,s1;
	while(sp >> s)
	if( s == "%1" ) { if( ! (sm >> *p1) ) return false; continue; }
	else if( s == "%2" ) 
	{ 
		T2 t2;
		p2->clear();
		while(sm >> t2) p2->push_back(t2);
	}
	else { if ( (!(sm >> s1)) || (s1 != s) ) return false; }
	return true;
}
template<typename T1,typename T2,typename T3>
bool match(const std::string & pattern,const std::string & m,T1*p1,T2*p2,T3*p3)
{
	std::istringstream sp(pattern),sm(m);
	std::string s,s1;
	while(sp >> s)
	if( s == "%1" ) { if( ! (sm >> *p1) ) return false; continue; }
	else if( s == "%2" ) { if( ! (sm >> *p2) ) return false; continue; }
	else if( s == "%3" ) { if( ! (sm >> *p3) ) return false; continue; }
	else { if ( (!(sm >> s1)) || (s1 != s) ) return false; }
	return true;
}

template<typename T1,typename T2,typename T3>
bool match(const std::string & pattern,const std::string & m,T1*p1,T2*p2,std::vector<T3>*p3)
{
	std::istringstream sp(pattern),sm(m);
	std::string s,s1;
	while(sp >> s)
	if( s == "%1" ) { if( ! (sm >> *p1) ) return false; continue; }
	else if( s == "%2" ) { if( ! (sm >> *p2) ) return false; continue; }
	else if( s == "%3" ) 
	{ 
		T3 t3;
		p3->clear();
		while(sm >> t3) p3->push_back(t3);
	}
	else { if ( (!(sm >> s1)) || (s1 != s) ) return false; }
	return true;
}
template<typename T1,typename T2,typename T3,typename T4>
bool match(const std::string & pattern,const std::string & m,T1*p1,T2*p2,T3*p3,T4*p4)
{
	std::istringstream sp(pattern),sm(m);
	std::string s,s1;
	while(sp >> s)
	if( s == "%1" ) { if( ! (sm >> *p1) ) return false; continue; }
	else if( s == "%2" ) { if( ! (sm >> *p2) ) return false; continue; }
	else if( s == "%3" ) { if( ! (sm >> *p3) ) return false; continue; }
	else if( s == "%4" ) { if( ! (sm >> *p4) ) return false; continue; }

	else { if ( (!(sm >> s1)) || (s1 != s) ) return false; }
	return true;
}
template<typename T1,typename T2,typename T3,typename T4>
bool match(const std::string & pattern,const std::string & m,T1*p1,T2*p2,T3*p3,std::vector<T4>*p4)
{
	std::istringstream sp(pattern),sm(m);
	std::string s,s1;
	while(sp >> s)
	if( s == "%1" ) { if( ! (sm >> *p1) ) return false; continue; }
	else if( s == "%2" ) { if( ! (sm >> *p2) ) return false; continue; }
	else if( s == "%3" ) { if( ! (sm >> *p3) ) return false; continue; }
	else if( s == "%4" ) 
	{ 
		T4 t4;
		p4->clear();
		while(sm >> t4) p4->push_back(t4);
	}
	else { if ( (!(sm >> s1)) || (s1 != s) ) return false; }
	return true;
}

template<typename T1,typename T2,typename T3,typename T4,typename T5>
bool match(const std::string & pattern,const std::string & m,T1*p1,T2*p2,T3*p3,T4*p4,T5*p5)
{
	std::istringstream sp(pattern),sm(m);
	std::string s,s1;
	while(sp >> s)
	if( s == "%1" ) { if( ! (sm >> *p1) ) return false; continue; }
	else if( s == "%2" ) { if( ! (sm >> *p2) ) return false; continue; }
	else if( s == "%3" ) { if( ! (sm >> *p3) ) return false; continue; }
	else if( s == "%4" ) { if( ! (sm >> *p4) ) return false; continue; }
	else if( s == "%5" ) { if( ! (sm >> *p5) ) return false; continue; }
	else { if ( (!(sm >> s1)) || (s1 != s) ) return false; }
	return true;
}

template<typename T1,typename T2,typename T3,typename T4,typename T5,typename T6,typename T7,typename T8,typename T9>
bool match(const std::string & pattern,const std::string & m,T1*p1,T2*p2,T3*p3,T4*p4,T5*p5,T6*p6,T7*p7,T8*p8,T9*p9)
{
	std::istringstream sp(pattern),sm(m);
	std::string s,s1;
	while(sp >> s)
	if( s == "%1" ) { if( ! (sm >> *p1) ) return false; continue; }
	else if( s == "%2" ) { if( ! (sm >> *p2) ) return false; continue; }
	else if( s == "%3" ) { if( ! (sm >> *p3) ) return false; continue; }
	else if( s == "%4" ) { if( ! (sm >> *p4) ) return false; continue; }
	else if( s == "%5" ) { if( ! (sm >> *p5) ) return false; continue; }
	else if( s == "%6" ) { if( ! (sm >> *p6) ) return false; continue; }
	else if( s == "%7" ) { if( ! (sm >> *p7) ) return false; continue; }
	else if( s == "%8" ) { if( ! (sm >> *p8) ) return false; continue; }
	else if( s == "%9" ) { if( ! (sm >> *p9) ) return false; continue; }
	else { if ( (!(sm >> s1)) || (s1 != s) ) return false; }
	return true;
}


template<typename T1,typename T2,typename T3,typename T4,typename T5,typename T6,typename T7,typename T8,typename T9,typename T10>
bool match(const std::string & pattern,const std::string & m,T1*p1,T2*p2,T3*p3,T4*p4,T5*p5,T6*p6,T7*p7,T8*p8,T9*p9,T10*p10)
{
	std::istringstream sp(pattern),sm(m);
	std::string s,s1;
	while(sp >> s)
	if( s == "%1" ) { if( ! (sm >> *p1) ) return false; continue; }
	else if( s == "%2" ) { if( ! (sm >> *p2) ) return false; continue; }
	else if( s == "%3" ) { if( ! (sm >> *p3) ) return false; continue; }
	else if( s == "%4" ) { if( ! (sm >> *p4) ) return false; continue; }
	else if( s == "%5" ) { if( ! (sm >> *p5) ) return false; continue; }
	else if( s == "%6" ) { if( ! (sm >> *p6) ) return false; continue; }
	else if( s == "%7" ) { if( ! (sm >> *p7) ) return false; continue; }
	else if( s == "%8" ) { if( ! (sm >> *p8) ) return false; continue; }
	else if( s == "%9" ) { if( ! (sm >> *p9) ) return false; continue; }
	else if( s == "%10" ) { if( ! (sm >> *p10) ) return false; continue; }
	else { if ( (!(sm >> s1)) || (s1 != s) ) return false; }
	return true;
}



template<typename T1,typename T2,typename T3,typename T4,typename T5>
bool match(const std::string & pattern,const std::string & m,T1*p1,T2*p2,T3*p3,T4*p4,std::vector<T5>*p5)
{
	std::istringstream sp(pattern),sm(m);
	std::string s,s1;
	while(sp >> s)
	if( s == "%1" ) { if( ! (sm >> *p1) ) return false; continue; }
	else if( s == "%2" ) { if( ! (sm >> *p2) ) return false; continue; }
	else if( s == "%3" ) { if( ! (sm >> *p3) ) return false; continue; }
	else if( s == "%4" ) { if( ! (sm >> *p4) ) return false; continue; }
	else if( s == "%5" ) 
	{ 
		T5 t5;
		p5->clear();
		while(sm >> t5) p5->push_back(t5);
	}
	else { if ( (!(sm >> s1)) || (s1 != s) ) return false; }
	return true;
}

//! match function
//! it matches a pattern against a string
//! @param pattern contains the pattern, the output pattern %1 (%2,%3,...)
//! @param d delimiters that counts as whitespace
//! @param m contains the string
//! @param p1 output pointer with T type that takes the value form %1
//! @return true if match was succesfull
template<typename T1,typename T2>
bool match(std::string pattern,const char d,std::string m,T1*p1,T2*p2)
{
	std::replace(m.begin(),m.end(),d,' ');
	std::replace(pattern.begin(),pattern.end(),d,' ');
	std::istringstream sp(pattern),sm(m);
	std::string s,s1;
	while(sp >> s)
	if( s == "%1" ) { if( ! (sm >> *p1) ) return false; continue; }
	else if( s == "%2" ) { if( ! (sm >> *p2) ) return false; continue; }
	else { if ( (!(sm >> s1)) || (s1 != s) ) return false; }
	return true;
}
template<typename T1,typename T2,typename T3>
bool match(std::string pattern,const char d,std::string m,T1*p1,T2*p2,T3*p3)
{
	std::replace(m.begin(),m.end(),d,' ');
	std::replace(pattern.begin(),pattern.end(),d,' ');
	std::istringstream sp(pattern),sm(m);
	std::string s,s1;
	while(sp >> s)
	if( s == "%1" ) { if( ! (sm >> *p1) ) return false; continue; }
	else if( s == "%2" ) { if( ! (sm >> *p2) ) return false; continue; }
	else if( s == "%3" ) { if( ! (sm >> *p3) ) return false; continue; }
	else { if ( (!(sm >> s1)) || (s1 != s) ) return false; }
	return true;
}
template<typename T1,typename T2,typename T3,typename T4>
bool match(std::string pattern,const char d,std::string m,T1*p1,T2*p2,T3*p3,T4*p4)
{
	std::replace(m.begin(),m.end(),d,' ');
	std::replace(pattern.begin(),pattern.end(),d,' ');
	std::istringstream sp(pattern),sm(m);
	std::string s,s1;
	while(sp >> s)
	if( s == "%1" ) { if( ! (sm >> *p1) ) return false; continue; }
	else if( s == "%2" ) { if( ! (sm >> *p2) ) return false; continue; }
	else if( s == "%3" ) { if( ! (sm >> *p3) ) return false; continue; }
	else if( s == "%4" ) { if( ! (sm >> *p4) ) return false; continue; }
	else { if ( (!(sm >> s1)) || (s1 != s) ) return false; }
	return true;
}
template<typename T1,typename T2,typename T3,typename T4,typename T5>
bool match(std::string pattern,const char d,std::string m,T1*p1,T2*p2,T3*p3,T4*p4,T5*p5)
{
	std::replace(m.begin(),m.end(),d,' ');
	std::replace(pattern.begin(),pattern.end(),d,' ');
	std::istringstream sp(pattern),sm(m);
	std::string s,s1;
	while(sp >> s)
	if( s == "%1" ) { if( ! (sm >> *p1) ) return false; continue; }
	else if( s == "%2" ) { if( ! (sm >> *p2) ) return false; continue; }
	else if( s == "%3" ) { if( ! (sm >> *p3) ) return false; continue; }
	else if( s == "%4" ) { if( ! (sm >> *p4) ) return false; continue; }
	else if( s == "%5" ) { if( ! (sm >> *p5) ) return false; continue; }
	else { if ( (!(sm >> s1)) || (s1 != s) ) return false; }
	return true;
}

}
#endif // SIMPLE_IO_H

